package service

import (
	"context"
	"fmt"
	"path/filepath"
	"strings"
	"time"

	"gitee.com/fu-ce-wei/pi-mapper/dto"
	"gitee.com/fu-ce-wei/pi-mapper/internal/config"
	"gitee.com/fu-ce-wei/pi-mapper/pkg/logger"
	"gitee.com/fu-ce-wei/pi-mapper/pkg/redis"
	"go.uber.org/zap"
)

// ImageService 图片服务接口
type ImageService interface {
	// GetImageList 获取图片列表
	GetImageList(ctx context.Context, count int) (*dto.ImageListResponse, error)

	// GetImageURL 获取图片完整URL
	GetImageURL(filename string) string

	// ValidateImageFile 验证图片文件
	ValidateImageFile(filename string) bool

	// GetImageInfo 获取图片信息
	GetImageInfo(ctx context.Context, filename string) (*dto.ImageResponse, error)
}

// imageServiceImpl 图片服务实现
type imageServiceImpl struct {
	redisClient *redis.Client
	config      *config.Config
	logger      *logger.Logger
}

// NewImageService 创建图片服务实例
func NewImageService(redisClient *redis.Client, config *config.Config, logger *logger.Logger) ImageService {
	return &imageServiceImpl{
		redisClient: redisClient,
		config:      config,
		logger:      logger,
	}
}

// GetImageList 获取图片列表
func (s *imageServiceImpl) GetImageList(ctx context.Context, count int) (*dto.ImageListResponse, error) {
	if count <= 0 {
		count = 5
	}
	if count > 20 {
		count = 20
	}

	// 记录请求日志
	s.logger.Info("开始获取图片列表",
		zap.Int("requested_count", count),
		zap.String("redis_key", s.config.Image.RedisKey),
	)

	// 从Redis获取随机图片
	filenames, err := s.redisClient.GetRandomVideos(ctx, s.config.Image.RedisKey, count)
	if err != nil {
		s.logger.Error("获取随机图片失败",
			zap.Error(err),
			zap.String("redis_key", s.config.Image.RedisKey),
		)
		return nil, fmt.Errorf("获取图片列表失败: %w", err)
	}

	// 如果没有找到图片
	if len(filenames) == 0 {
		s.logger.Warn("没有找到图片文件",
			zap.String("redis_key", s.config.Image.RedisKey),
		)
		return &dto.ImageListResponse{
			Images: []dto.ImageResponse{},
			URLs:   []string{},
			Total:  0,
			Count:  0,
		}, nil
	}

	// 构建响应
	images := make([]dto.ImageResponse, 0, len(filenames))
	urls := make([]string, 0, len(filenames))

	for _, filename := range filenames {
		// 验证文件名
		if !s.ValidateImageFile(filename) {
			s.logger.Warn("跳过无效的图片文件名",
				zap.String("filename", filename),
			)
			continue
		}

		// 获取图片URL
		imageURL := s.GetImageURL(filename)

		// 构建图片响应
		image := dto.ImageResponse{
			Name: filename,
			URL:  imageURL,
		}

		images = append(images, image)
		urls = append(urls, imageURL)
	}

	// 获取总数
	total, err := s.redisClient.GetVideoCount(ctx, s.config.Image.RedisKey)
	if err != nil {
		s.logger.Error("获取图片总数失败",
			zap.Error(err),
			zap.String("redis_key", s.config.Image.RedisKey),
		)
		// 不返回错误，使用0作为总数
		total = 0
	}

	response := &dto.ImageListResponse{
		Images: images,
		URLs:   urls,
		Total:  int(total),
		Count:  len(images),
	}

	s.logger.Info("成功获取图片列表",
		zap.Int("returned_count", len(images)),
		zap.Int64("total_count", total),
	)

	return response, nil
}

// GetImageURL 获取图片完整URL
func (s *imageServiceImpl) GetImageURL(filename string) string {
	// 清理文件名，防止路径遍历攻击
	filename = filepath.Base(filename)

	// 拼接URL
	return fmt.Sprintf("%s/%s", strings.TrimRight(s.config.Image.BaseURL, "/"), filename)
}

// ValidateImageFile 验证图片文件
func (s *imageServiceImpl) ValidateImageFile(filename string) bool {
	if filename == "" {
		return false
	}

	// 检查文件扩展名
	ext := strings.ToLower(filepath.Ext(filename))
	validExtensions := s.config.Image.FileExtensions

	for _, validExt := range validExtensions {
		if ext == strings.ToLower(validExt) {
			return true
		}
	}

	return false
}

// GetImageInfo 获取图片信息
func (s *imageServiceImpl) GetImageInfo(ctx context.Context, filename string) (*dto.ImageResponse, error) {
	if !s.ValidateImageFile(filename) {
		return nil, fmt.Errorf("无效的图片文件名: %s", filename)
	}

	// 构建完整文件路径
	filePath := filepath.Join(s.config.Image.RootPath, filename)

	// 检查文件是否存在
	info, err := getFileInfo(filePath)
	if err != nil {
		s.logger.Error("获取文件信息失败",
			zap.String("filename", filename),
			zap.String("path", filePath),
			zap.Error(err),
		)
		return nil, fmt.Errorf("获取文件信息失败: %w", err)
	}

	return &dto.ImageResponse{
		Name:      filename,
		URL:       s.GetImageURL(filename),
		Size:      info.Size,
		CreatedAt: info.ModTime,
	}, nil
}

// ImageStats 图片统计信息
type ImageStats struct {
	TotalImages int64
	TotalSize   int64
	LastUpdated time.Time
	OldestImage string
	NewestImage string
}

// GetImageStats 获取图片统计信息
func (s *imageServiceImpl) GetImageStats(ctx context.Context) (*ImageStats, error) {
	// 获取图片总数
	total, err := s.redisClient.GetVideoCount(ctx, s.config.Image.RedisKey)
	if err != nil {
		return nil, fmt.Errorf("获取图片总数失败: %w", err)
	}

	// TODO: 可以实现更详细的统计信息
	return &ImageStats{
		TotalImages: total,
		LastUpdated: time.Now(),
	}, nil
}

// RefreshImageCache 刷新图片缓存
func (s *imageServiceImpl) RefreshImageCache(ctx context.Context) error {
	// 清除Redis缓存
	err := s.redisClient.ClearVideos(ctx, s.config.Image.RedisKey)
	if err != nil {
		return fmt.Errorf("清除缓存失败: %w", err)
	}

	s.logger.Info("图片缓存已刷新",
		zap.String("redis_key", s.config.Image.RedisKey),
	)

	return nil
}

// AddImageToCache 手动添加图片到缓存
func (s *imageServiceImpl) AddImageToCache(ctx context.Context, filename string) error {
	if !s.ValidateImageFile(filename) {
		return fmt.Errorf("无效的图片文件名: %s", filename)
	}

	err := s.redisClient.AddVideo(ctx, s.config.Image.RedisKey, filename)
	if err != nil {
		return fmt.Errorf("添加图片到缓存失败: %w", err)
	}

	s.logger.Info("图片已添加到缓存",
		zap.String("filename", filename),
		zap.String("redis_key", s.config.Image.RedisKey),
	)

	return nil
}

// RemoveImageFromCache 从缓存中移除图片
func (s *imageServiceImpl) RemoveImageFromCache(ctx context.Context, filename string) error {
	err := s.redisClient.RemoveVideo(ctx, s.config.Image.RedisKey, filename)
	if err != nil {
		return fmt.Errorf("从缓存中移除图片失败: %w", err)
	}

	s.logger.Info("图片已从缓存中移除",
		zap.String("filename", filename),
		zap.String("redis_key", s.config.Image.RedisKey),
	)

	return nil
}
